package com.ai.bitcoin.utils;


import org.apache.commons.math3.stat.descriptive.moment.Mean;
import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation;
import org.apache.commons.math3.stat.descriptive.moment.Variance;
import org.apache.commons.math3.stat.descriptive.rank.Max;
import org.apache.commons.math3.stat.descriptive.rank.Min;
import org.apache.commons.math3.stat.descriptive.rank.Percentile;
import org.apache.commons.math3.stat.descriptive.summary.Product;
import org.apache.commons.math3.stat.descriptive.summary.Sum;

import java.math.BigDecimal;

/**
 * @author Jason
 * @date 2018.4.19
 **/
public class MathUtil {

    private static StandardDeviation standardDeviation = new StandardDeviation();//标准差
    private static Variance variance = new Variance();//方差
    private static Min min = new Min();
    private static Max max = new Max();
    private static Mean mean = new Mean(); // 算术平均值
    private static Product product = new Product();//乘积
    private static Sum sum = new Sum();//和
    private static Percentile percentile = new Percentile(); // 百分位数

    public static double mean(double values[]) {
        if (values == null || values.length == 0)
            return 0;
        return mean.evaluate(values);
    }

    public static double standardDeviation(double values[]) {
        if (values == null || values.length == 0)
            return 0;
        return standardDeviation.evaluate(values);
    }

    public static double variance(double values[]) {
        if (values == null || values.length == 0)
            return 0;
        return variance.evaluate(values);
    }

    public static double min(double values[]) {
        if (values == null || values.length == 0)
            return 0;
        return min.evaluate(values);
    }

    public static double sum(double values[]) {
        if (values == null || values.length == 0)
            return 0;
        return sum.evaluate(values);
    }

    public static double percentile(double values[], double percent) {
        if (values == null || values.length == 0)
            return 0;
        return percentile.evaluate(values, percent);
    }

    public static double max(double values[]) {
        if (values == null || values.length == 0)
            return 0;
        return max.evaluate(values);
    }

    /**
     * 提供精确的小数位四舍五入处理。
     *
     * @param v
     *            需要四舍五入的数字
     * @param scale
     *            小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static double round(double v, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b = new BigDecimal(Double.toString(v));
        BigDecimal one = new BigDecimal("1");
        return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }


    /**
     * 提供精確的加法運算
     */
    public static double add(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2).doubleValue();
    }

    /**
     * 提供了精確的減法運算
     *
     */
    public static double sub(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2).doubleValue();
    }

    /**
     * 提供了精確的乘法運算
     */
    public static double mul(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.multiply(b2).doubleValue();
    }

    /**
     * 提供了(相對)精確的除法運算，當發生除不儘的情況時，精確到
     * 小數點以後１10位
     */
    public static double div(double v1, double v2) {
        return div(v1, v2, 2);
    }

    /**
     * 提供了(相對)精確的除法運算，當發生除不儘的情況時，由scale參數指定
     * 精度，以後的數字四捨五入
     */
    public static double div(double v1, double v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    public static void main(String[] args) {
//        System.out.println(add(1.2321231, 3.7865765));
//        System.out.println(sub(6.4523423, 1.2321231));
//        System.out.println(mul(6.4523423, 3.7865765));
//        System.out.println(div(6.4523423, 3.7865765, 5));
//        System.out.println(round(3.7865765, 5));
       double a = Math.random();
        System.out.println(a);
        double rate = MathUtil.div(2+1-a,30,6);
        System.out.println(rate);
        System.out.println(MathUtil.sub(1,rate));
    }
}
